package com.gitee.sunshine.aop;


import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ImportResource;
import org.springframework.stereotype.Component;

import com.gitee.sunshine.annotation.ReadDB;
import com.gitee.sunshine.bean.DBContextHolder;
import com.gitee.sunshine.enums.DBTypeEnum;
import com.gitee.sunshine.factory.ServiceInvocationContext;
import com.gitee.sunshine.factory.ServiceInvocationContextFactory;

@Component
@ImportResource(locations= {"classpath:application-bean.xml"})
public class DataSourceInterceptor implements MethodInterceptor {
	private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceInterceptor.class);
	
	@Autowired
	private ServiceInvocationContextFactory contextFactory;

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		
		String className = invocation.getThis().getClass().getName();
		String methodName = invocation.getMethod().getName();
		Annotation annotation = null;
		DBTypeEnum dbTypeEnum = DBContextHolder.get();
		if(null == dbTypeEnum){
			// 因为只有dbTypeEnum为null时才需要去获取当前方法上的注解否则，已之前设置过的为主
			annotation = getAnnotation(invocation, methodName);
			LOGGER.info("current method annotation:{}",annotation);
		}	
		
		LOGGER.info("className:{},methodName:{},currentDBType:{}",className,methodName,dbTypeEnum);
		if (null == dbTypeEnum && null == annotation) {
			DBContextHolder.master();
		} else if (null == dbTypeEnum && null != annotation) {
			DBContextHolder.slave();
		}
		LOGGER.info("finally DBType:{}",DBContextHolder.get());
		ServiceInvocationContext context = contextFactory.getContext();
		context.createInvocation(invocation);
		try {
			return invocation.proceed();
		} catch (Exception e) {
			throw e;
		} finally {
			context.endCurrentInvocation(invocation);
			if (context.serviceEnd()) {
				context.clean();
				DBContextHolder.clear();
			}
		}
	}

	private Annotation getAnnotation(MethodInvocation invocation, String methodName) {
		Method[] methods = invocation.getThis().getClass().getMethods();
		for (Method method : methods) {
			if(method.getName().equals(methodName)){
				return method.getAnnotation(ReadDB.class);
			}
		}
		return null;
	}

}
